#include "../emsdk/upstream/emscripten/system/include/emscripten/bind.h"
#include <string>
#include "./math/vec3.h"
#include "./math/quat.h"
#include "./scene/node.h"
#include "./engine.h"
#include "./physics/physics-enum.h"
#include "./physics/physics.h"
#include "./physics/collider-box.h"
#include "./physics/collider-sphere.h"
#include "./geometry/aabb.h"
#include "./geometry/intersect3d.h"

using namespace emscripten;

#ifdef __EMSCRIPTEN__

// 绑定 Math 类到 JavaScript
EMSCRIPTEN_BINDINGS(Math)
{
    class_<Vec3>("Vec3")
        .constructor<>()
        .constructor<float, float, float>()
        .function("set", &Vec3::set)
        .function("getX", &Vec3::getX)
        .function("getY", &Vec3::getY)
        .function("getZ", &Vec3::getZ)
        .function("test", &Vec3::test)
        .smart_ptr<std::shared_ptr<Vec3>>("shared_ptr<Vec3>");

    class_<Quat>("Quat")
        .constructor<>()
        .function("set", &Quat::set)
        .function("getX", &Quat::getX)
        .function("getY", &Quat::getY)
        .function("getZ", &Quat::getZ)
        .function("getW", &Quat::getW)
        .smart_ptr<std::shared_ptr<Quat>>("shared_ptr<Quat>");
}

EMSCRIPTEN_BINDINGS(Geometry)
{
    class_<AABB>("AABB")
        .constructor<>()
        .function("setCenter", &AABB::setCenter)
        .function("getCenter", &AABB::getCenter, emscripten::allow_raw_pointers())
        .function("setHalfExtents", &AABB::setHalfExtents)
        .function("getHalfExtents", &AABB::getHalfExtents, emscripten::allow_raw_pointers())
        .smart_ptr<std::shared_ptr<AABB>>("shared_ptr<AABB>");

    class_<Intersect3D>("Intersect3D")
        .class_function("aabbWithAABB", &Intersect3D::aabbWithAABB, emscripten::allow_raw_pointers()); // const result = Module.Intersect3D.aabbWithAABB(aabb1, aabb2); // 直接通过类名调用
}

// 绑定 Node 类到 JavaScript
EMSCRIPTEN_BINDINGS(Scene)
{
    class_<Node>("Node")
        // .constructor<std::string>()
        .function("setPosition", &Node::setPosition)
        .function("setScale", &Node::setScale)
        .function("setRotation", &Node::setRotation)
        .function("initModel", &Node::initModel)
        .function("addBoxCollider", &Node::addBoxCollider, emscripten::allow_raw_pointers())
        .function("addSphereCollider", &Node::addSphereCollider, emscripten::allow_raw_pointers())
        .function("delCollider", &Node::delCollider)
        .function("getCollider", &Node::getCollider, emscripten::allow_raw_pointers())
        .smart_ptr<std::shared_ptr<Node>>("shared_ptr<Node>");
}

// 绑定 Physics 类到 JavaScript
EMSCRIPTEN_BINDINGS(Physics)
{
    enum_<PhysicsColliderType>("PhysicsColliderType")
        .value("STATIC", PhysicsColliderType::STATIC)
        .value("KINEMATICS", PhysicsColliderType::KINEMATICS);

    enum_<PhysicsColliderGeometry>("PhysicsColliderGeometry")
        .value("Plane", PhysicsColliderGeometry::Plane)
        .value("Box", PhysicsColliderGeometry::Box)
        .value("Capsule", PhysicsColliderGeometry::Capsule)
        .value("Cylinder", PhysicsColliderGeometry::Cylinder)
        .value("Sphere", PhysicsColliderGeometry::Sphere);

    class_<ColliderBase>("ColliderBase")

        .function("setGroup", &ColliderBase::setGroup)
        .function("getGroup", &ColliderBase::getGroup)

        .function("setMask", &ColliderBase::setMask)
        .function("getMask", &ColliderBase::getMask)

        .function("setType", &ColliderBase::setType)
        .function("getType", &ColliderBase::getType)

        .function("getAABB", &ColliderBase::getAABB, emscripten::allow_raw_pointers())

        .function("setColliderCallback", &ColliderBase::setColliderCallback)
        .function("clearColliderCallback", &ColliderBase::clearColliderCallback)

        .function("destroy", &ColliderBase::destroy)
        .smart_ptr<std::shared_ptr<ColliderBase>>("shared_ptr<ColliderBase>");

    class_<ColliderBox, base<ColliderBase>>("ColliderBox")
        .constructor<Node *>()
        .smart_ptr<std::shared_ptr<ColliderBox>>("shared_ptr<ColliderBox>")
        // 继承的方法会自动绑定，无需重复声明
        // 可添加派生类特有方法
        ;
    class_<ColliderSphere, base<ColliderBase>>("ColliderSphere")
        .constructor<Node *>()
        .smart_ptr<std::shared_ptr<ColliderSphere>>("shared_ptr<ColliderSphere>")
        // 继承的方法会自动绑定，无需重复声明
        // 可添加派生类特有方法
        ;

    class_<Physics>("Physics")
        .constructor<>()
        .function("update", &Physics::update);
}

// 绑定 Carlos 类到 JavaScript
EMSCRIPTEN_BINDINGS(Engine)
{
    class_<Engine>("Engine")
        .constructor<>()
        .function("addNode", &Engine::addNode, emscripten::allow_raw_pointers())
        .function("delNode", &Engine::delNode)
        .function("getNode", &Engine::getNode, emscripten::allow_raw_pointers())
        .function("cleanAllNode", &Engine::cleanAllNode)
        .function("openPhysics", &Engine::openPhysics)
        .function("closePhysics", &Engine::closePhysics)
        .function("update", &Engine::update);
}
#endif
